package de.akabahn.ebd.fst;

import java.util.ArrayList;
import java.util.List;

/**
 * Class representing one "Triebfahrzeug" with its attributes
 * 
 * @author Peter Eimann
 * @since 0.1
 * @version 1.0
 */
public class Tfz {

	/**
	 * Operation mode<br>
	 * <code>MANUAL</code> equals to "Manuell" <br>
	 * <code>AUTO</code> equals to "Automatisch" <br>
	 * <code>MULTITRACTION</code> equals to "Multitraktion"
	 */
	public static enum Mode {
		MANUAL, AUTO, MULTITRACTION;
	}

	/**
	 * Direction<br>
	 * <code>REVERSE</code> equals to "Pfeilr &lt;=" or value 0<br>
	 * <code>ARROW</code> equals to "Pfeilr =&gt;" or value 1
	 */
	public static enum Direction {
		REVERSE(0), ARROW(1);

		private int value;

		Direction(int value) {
			this.value = value;
		}

		public int getValue() {
			return value;
		}

		/**
		 * Get the <code>Direction</code> enum from the passed
		 * <code>value</code>
		 * 
		 * @param value
		 *            The value
		 * @return <code>REVERSE</code> for value 0, <code>ARROW</code> for
		 *         value 1 and <code>null</code> for all other values
		 */
		public static Direction fromValue(int value) {
			switch (value) {
			case 0:
				return REVERSE;
			case 1:
				return ARROW;
			default:
				return null;
			}
		}
	}

	// Tfz-Adresse
	private String address;
	// Fahrmodus
	private Mode mode;
	// Richtung
	private Direction direction;
	// Umkehr aktiv
	private boolean reverse;
	// Hold aktiv
	private boolean hold;
	// Wait aktiv
	private boolean wait;
	// Befehl 2 aktiv
	private boolean befehl2;
	// Fahrstufe
	private int speed;
	// Ort
	private String location;
	// Steuerndes Tfz bei Multitraktion
	private Tfz master;
	// Gesteuerte Tfz bei Multitraktion
	private List<Tfz> slaves;
	// Special functions
	private boolean[] function;
	// Fahrbereit
	private boolean ready;
	// Handregler number
	private int handregler;
	// Tfz ist steuerndes Tfz bei Multitraktion
	private boolean masterTfz;
	// Tfz ist gesteuertes Tfz bei Multitraktion
	private boolean slaveTfz;

	public Tfz() {
		slaves = new ArrayList<Tfz>();
		function = new boolean[5];
	}

	/**
	 * @return the address
	 */
	public String getAddress() {
		return address;
	}

	/**
	 * @param address
	 *            the address to set
	 */
	public void setAddress(String address) {
		this.address = address;
	}

	/**
	 * @return the mode
	 */
	public Mode getMode() {
		return mode;
	}

	/**
	 * @param mode
	 *            the mode to set
	 */
	public void setMode(Mode mode) {
		this.mode = mode;
	}

	/**
	 * @return the direction
	 */
	public Direction getDirection() {
		return direction;
	}

	/**
	 * @param direction
	 *            the direction to set
	 */
	public void setDirection(Direction direction) {
		this.direction = direction;
	}

	/**
	 * @return the reverse
	 */
	public boolean isReverse() {
		return reverse;
	}

	/**
	 * @param reverse
	 *            the reverse to set
	 */
	public void setReverse(boolean reverse) {
		this.reverse = reverse;
	}

	/**
	 * @return the hold
	 */
	public boolean isHold() {
		return hold;
	}

	/**
	 * @param hold
	 *            the hold to set
	 */
	public void setHold(boolean hold) {
		this.hold = hold;
	}

	/**
	 * @return the wait
	 */
	public boolean isWait() {
		return wait;
	}

	/**
	 * @param wait
	 *            the wait to set
	 */
	public void setWait(boolean wait) {
		this.wait = wait;
	}

	/**
	 * @return the befehl2
	 */
	public boolean isBefehl2() {
		return befehl2;
	}

	/**
	 * @param befehl2
	 *            the befehl2 to set
	 */
	public void setBefehl2(boolean befehl2) {
		this.befehl2 = befehl2;
	}

	/**
	 * @return the speed
	 */
	public int getSpeed() {
		return speed;
	}

	/**
	 * @param speed
	 *            the speed to set
	 */
	public void setSpeed(int speed) {
		this.speed = speed;
	}

	/**
	 * @return the location
	 */
	public String getLocation() {
		return location;
	}

	/**
	 * @param location
	 *            the location to set
	 */
	public void setLocation(String location) {
		this.location = location;
	}

	/**
	 * @return the master
	 */
	public Tfz getMaster() {
		return master;
	}

	/**
	 * @param master
	 *            the master to set
	 */
	public void setMaster(Tfz master) {
		this.master = master;
	}

	/**
	 * @return the ready
	 */
	public boolean isReady() {
		return ready;
	}

	/**
	 * @param ready
	 *            the ready to set
	 */
	public void setReady(boolean ready) {
		this.ready = ready;
	}

	/**
	 * @return the handregler
	 */
	public int getHandregler() {
		return handregler;
	}

	/**
	 * @param handregler
	 *            the handregler to set
	 */
	public void setHandregler(int handregler) {
		this.handregler = handregler;
	}

	/**
	 * @return the slaves
	 */
	public List<Tfz> getSlaves() {
		return slaves;
	}

	/**
	 * @return the function
	 */
	public boolean[] getFunction() {
		return function;
	}

	/**
	 * @return the masterTfz
	 */
	public boolean isMasterTfz() {
		return masterTfz;
	}

	/**
	 * @param masterTfz the masterTfz to set
	 */
	public void setMasterTfz(boolean masterTfz) {
		this.masterTfz = masterTfz;
	}

	/**
	 * @return the slaveTfz
	 */
	public boolean isSlaveTfz() {
		return slaveTfz;
	}

	/**
	 * @param slaveTfz the slaveTfz to set
	 */
	public void setSlaveTfz(boolean slaveTfz) {
		this.slaveTfz = slaveTfz;
	}

	/**
	 * Return a string representation of the "Triebfahrzeug"
	 */
	public String toString() {
		String slaveStr = "";
		String functionStr = "";

		if (slaves.isEmpty()) {
			slaveStr = "-";
		} else {
			for (Tfz tfz : slaves) {
				slaveStr += tfz.getAddress();
				slaveStr += ", ";
			}
			slaveStr = slaveStr.substring(0, slaveStr.length() - 2);
		}

		for (int index = 0; index < function.length; index++) {
			functionStr += function[index] ? Integer.toString(index) : "-";
		}

		return "Tfz [ADDR=" + address + ", MODE=" + mode + ", DIR=" + direction
				+ ", UMK=" + reverse + ", SPEED=" + speed + ", LOC=" + location
				+ ", HOLD=" + hold + ", WAIT=" + wait + ", BEF2=" + befehl2
				+ ", FAHRB=" + ready + ", HNDR="
				+ ((handregler == 0) ? "-" : handregler) + ", FUNC="
				+ functionStr + ", MASTER="
				+ ((master == null) ? "-" : master.getAddress()) + ", SLAVE="
				+ slaveStr + "]";
	}

	/**
	 * Return a string representation of the "Triebfahrzeug"
	 */
	public String prettyPrint() {
		String functionStr = "";

		for (int index = 0; index < function.length; index++) {
			functionStr += function[index] ? Integer.toString(index) : "-";
		}

		StringBuilder buf = new StringBuilder();
		buf.append("<").append(mode).append("> ");
		if (direction == Direction.ARROW) {
			buf.append("<PFEILR> ");
		} else {
			buf.append("<GEGENR> ");
		}
		if (reverse) {
			buf.append("<UMK> ");
		}
		if (!"-".equals(location)) {
			buf.append("<Ort ").append(location).append("> ");
		}
		buf.append("\n");
		buf.append("<Fst ").append(speed).append("> ");
		if (hold) {
			buf.append("<HOLD> ");
		}
		if (wait) {
			buf.append("<WAIT> ");
		}
		if (befehl2) {
			buf.append("<BEF2> ");
		}
		if (ready) {
			buf.append("<FAHRB> ");
		}
		if (handregler != 0) {
			buf.append("<Regler ").append(handregler).append("> ");
		}
		if (masterTfz) {
			buf.append("<MT> ");
		}
		buf.append("<F").append(functionStr).append(">");

		return buf.toString();
	}
}